package tms.unitTests;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import java.util.Calendar;
import java.util.Date;

import org.junit.Before;
import org.junit.Test;

import tms.model.Task;

/**
 * TaskUnitTests class contains the units tests of the methods in the Task class 
 * 
 * @author Rolf Schmidt
 *
 */
public class TaskUnitTests {
	/// a header line used in converting a person or a task to a string
	final String H_LINE = "---------------------------------------";
	/// format of the date
	final String DATE_FORMAT = "MM/dd/yyyy";
	/// a long task duration
	final int LONG_DURATION = 1548765412;
	/// number of characters in a long string
	final int LONG_STRING = 100;
	/// number of characters in a very long string
	final int VERY_LONG_STRING = 2000;
	/// a string containing wild characters
	final String WILD_STRING = "*@&(|}{+?~+\\/";
	/// stringbuffer for long string
	StringBuffer stringBufferLong;
	/// stringbuffer for a very long string
	StringBuffer stringBufferVeryLong;
	
	/**
	 * default constructor
	 */
	public TaskUnitTests() {
	}

	/**
	 * helper method called before every unit test to create a long and a very long string buffers
	 */
	@Before
	public void setUp() {
		stringBufferLong = new StringBuffer(LONG_STRING);
		for (int i = 0; i < LONG_STRING; i++) {
			stringBufferLong.append("a");
		}
		
		stringBufferVeryLong = new StringBuffer(VERY_LONG_STRING);
		for (int i = 0; i < VERY_LONG_STRING; i++) {
			stringBufferVeryLong.append("a");
		}
    }
	
	/**
	 * test the default values assigned to a task object in the task default constructor
	 */
	@Test
	public void testTaskConstructor() {
		Task task = new Task();
		
		assertEquals(0, task.getId());
		assertEquals("none", task.getTitle());
		assertEquals("none", task.getDescription());
		assertEquals(1, task.getDuration());
		assertEquals("none", task.getDeliverable());
		assertEquals("nobody", task.getPerson());
		assertEquals(null, task.getParent());
		assertEquals(-1, task.getBeforeId());
	}

	/**
	 * test that a task object is equal to itself
	 */
	@Test
	public void testTaskEquals1() {
		Task task = new Task();
		assertTrue(task.equals(task));
	}
	
	/**
	 * test that two different task objects are not equal when all of their attributes are the same
	 * the ids and deadlines are set in the test and the rest of attributes are defaults
	 */
	@Test
	public void testTaskEquals2() {
		
		// create two tasks
		Task task1 = new Task();
		Task task2 = new Task();
		Date testDeadline = Calendar.getInstance().getTime();

		// set the same id and deadline to the tasks
		task1.setId(1);
		task1.setDeadline(testDeadline);
		task2.setId(1);
		task2.setDeadline(testDeadline);

		// test the equality
		assertFalse(task1.equals(task2));
	}
	
	/**
	 * test that two task objects are different if their ids are different
	 */
	@Test
	public void testTaskEquals3() {
		// create two tasks
		Task task1 = new Task();
		Task task2 = new Task();

		// set different ids to the tasks
		task1.setId(1);
		task2.setId(2);

		// test the inequality
		assertFalse(task1.equals(task2));
	}
	
	/**
	 * test that a task object is not equal to an object of different type
	 */
	@Test
	public void testTaskEquals4() {
		Task task = new Task();

		String test = "test different object";

		// test that task is not equal to string
		assertFalse(task.equals(test));
	}
	
	/**
	 * test that a task object is not equal to null 
	 */
	@Test
	public void testTaskEquals5() {
		Task task = new Task();
		assertFalse(task.equals(null));
	}
	
	/**
	 * test that two task objects are different if any of their attributes are different
	 * (id, title, description, deliverable, deadline, person name) 
	 */
	@Test
	public void testTaskEquals6() {
		Task task1 = new Task();
		Task task2 = new Task();
		Date testDeadline = Calendar.getInstance().getTime();

		task1.setDeadline(testDeadline);
		task2.setDeadline(testDeadline);

		// set different ids
		task1.setId(1);
		task2.setId(5);
		assertFalse(task1.equals(task2));
		// make them equal
		task2.setId(1); 
		
		// set different titles
		task1.setTitle("hi");
		task2.setTitle("bye");
		assertFalse(task1.equals(task2));
		// make them equal
		task2.setTitle("hi");
		
		// set different Descriptions
		task1.setDescription("des1");
		task2.setDescription("desc2");
		assertFalse(task1.equals(task2));
		// make them equal
		task2.setDescription("none");
		
		// set different deliverables
		task1.setDeliverable("del1");
		task2.setDeliverable("del2");
		assertFalse(task1.equals(task2));
		// make them equal
		task2.setDeliverable("none");
		
		// set different deadlines
		task2.setDeadline(null);
		assertFalse(task1.equals(task2));
		// make them equal
		task2.setDeadline(testDeadline);
		
		// set different person name
		task1.setPerson("sam");
		task2.setPerson(null);
		assertFalse(task1.equals(task2));
	}
	
	/**
	 * test setting id of the task to a positive number
	 * expect successful operation
	 */
	@Test
	public void testTaskSetId1() {
		Task task = new Task();
		
		task.setId(1);
		assertEquals(1, task.getId());
	}
	
	/**
	 * test setting id of the task to zero
	 * expect successful operation
	 */
	@Test
	public void testTaskSetId2() {
		Task task = new Task();
		
		task.setId(0);
		assertEquals(0, task.getId());
	}
	
	/**
	 * test setting id of the task to an invalid number (negative)
	 * expect successful operation; however, the id is set to a default value (zero)
	 */
	@Test
	public void testTaskSetId3() {
		Task task = new Task();

		task.setId(-1);
		assertEquals(0, task.getId());
	}
	
	/**
	 * test setting title of the task to an empty string
	 * expect successful operation; however, the title is set to a default value (none)
	 */
	@Test
	public void testTaskSetTitle1() {
		Task task = new Task();
		
		task.setTitle("");
		assertEquals("none", task.getTitle());
	}
	
	/**
	 * test setting title of the task to a long string
	 * expect successful operation
	 */
	@Test
	public void testTaskSetTitle2() {
		Task task = new Task();

		task.setTitle(stringBufferLong.toString());
		assertEquals(stringBufferLong.toString(), task.getTitle());
	}
	
	/**
	 * test setting title of the task to null
	 * expect successful operation; however, the title is set to a default value (none)
	 */
	@Test
	public void testTaskSetTitle3() {
		Task task = new Task();

		task.setTitle(null);
		assertEquals("none", task.getTitle());
	}
	
	/**
	 * test setting title of the task to a string containing wild characters
	 * expect successful operation
	 */
	@Test
	public void testTaskSetTitle4() {
		Task task = new Task();
		
		task.setTitle(WILD_STRING);
		assertEquals(WILD_STRING, task.getTitle());
	}
	
	/**
	 * test setting description of the task to an empty string
	 * expect successful operation; however, the description is set to a default value (none)
	 */
	@Test
	public void testTaskSetDescription1() {
		Task task = new Task();
		
		task.setDescription("");
		assertEquals("none", task.getDescription());
	}
	
	/**
	 * test setting description of the task to a very long string
	 * expect successful operation
	 */
	@Test
	public void testTaskSetDescription2() {
		Task task = new Task();
		
		task.setDescription(stringBufferVeryLong.toString());
		assertEquals(stringBufferVeryLong.toString(), task.getDescription());
	}
	
	/**
	 * test setting description of the task to null
	 * expect successful operation; however, the description is set to a default value (none)
	 */
	@Test
	public void testTaskSetDescription3() {
		Task task = new Task();

		task.setDescription(null);
		assertEquals("none", task.getDescription());
	}
	
	/**
	 * test setting description of the task to a string containing wild characters
	 * expect successful operation
	 */
	@Test
	public void testTaskSetDescription4() {
		Task task = new Task();
		
		task.setDescription(WILD_STRING);
		assertEquals(WILD_STRING, task.getDescription());
	}
	
	/**
	 * test setting duration of the task to a valid number (positive number greater than zero)
	 * expect successful operation
	 */
	@Test
	public void testTaskSetDuration1() {
		Task task = new Task();
		
		task.setDuration(10);
		assertTrue(task.getDuration() == 10);
	}
	
	/**
	 * test setting duration of the task to an invalid number (negative number)
	 * expect successful operation; however, the duration is set to a default value (1)
	 */
	@Test
	public void testTaskSetDuration2() {
		Task task = new Task();
		
		task.setDuration(-10);
		assertTrue(task.getDuration() == 1);
	}
	
	/**
	 * test setting duration of the task to an invalid number (zero)
	 * expect successful operation; however, the duration is set to a default value (1)
	 */
	@Test
	public void testTaskSetDuration3() {
		Task task = new Task();
		
		task.setDuration(0);
		assertTrue(task.getDuration() == 1);
	}
	
	/**
	 * test setting duration of the task to a valid number but very long duration
	 * expect successful operation
	 */
	@Test
	public void testTaskSetDuration4() {
		Task task = new Task();
		
		task.setDuration(LONG_DURATION);
		assertTrue(task.getDuration() == LONG_DURATION);
	}

	/**
	 * test setting duration of the task to a valid number but MAX integer value
	 * expect successful operation
	 */
	@Test
	public void testTaskSetDuration5() {
		Task task = new Task();
		
		task.setDuration(Integer.MAX_VALUE);
		assertTrue(task.getDuration() == Integer.MAX_VALUE);
	}
	
	/**
	 * test setting duration of the task to a positive number X, while the task
	 * has a subtask with duration Y and X > Y.
	 * expect successful operation and task duration = X
	 */
	@Test
	public void testTaskSetDuration6() {
		Task task = new Task();
		Task subTask = new Task();
		
		task.addSubtask(subTask);		
		subTask.setDuration(10);
		
		task.setDuration(20);
		
		assertTrue(task.getDuration() == 20);
	}

	/**
	 * test setting duration of the task to a positive number X, while the task
	 * has 3 subtasks with total duration Y and X > Y.
	 * expect successful operation and task duration = X
	 */
	@Test
	public void testTaskSetDuration7() {
		Task task = new Task();
		
		Task subTask1 = new Task();
		Task subTask2 = new Task();
		Task subTask3 = new Task();
		
		task.addSubtask(subTask1);
		task.addSubtask(subTask2);
		task.addSubtask(subTask3);
		
		subTask1.setDuration(1);
		subTask2.setDuration(2);
		subTask3.setDuration(3);
		
		task.setDuration(10);
		
		assertTrue(task.getDuration() == 10);
	}

	/**
	 * test setting duration of the task to a positive number X, while the task
	 * has 3 subtasks with total duration Y and X = Y.
	 * expect successful operation and task duration = X = Y
	 */
	@Test
	public void testTaskSetDuration8() {
		Task task = new Task();
		
		Task subTask1 = new Task();
		Task subTask2 = new Task();
		Task subTask3 = new Task();
		
		task.addSubtask(subTask1);
		task.addSubtask(subTask2);
		task.addSubtask(subTask3);
		
		subTask1.setDuration(1);
		subTask2.setDuration(2);
		subTask3.setDuration(3);
		
		task.setDuration(6);
		
		assertTrue(task.getDuration() == 6);
	}

	/**
	 * test setting duration of the task to a positive number X, while the task
	 * has 3 subtasks with total duration Y and X < Y.
	 * expect successful operation and task duration = Y
	 */
	@Test
	public void testTaskSetDuration9() {

		Task task = new Task();
		task.setId(1);
		task.setDuration(2);
		
		Task subTask1 = new Task();
		subTask1.setId(2);
		Task subTask2 = new Task();
		subTask2.setId(3);
		Task subTask3 = new Task();
		subTask3.setId(4);
		
		subTask1.setDuration(1);
		subTask2.setDuration(2);
		subTask3.setDuration(3);
		
		task.addSubtask(subTask1);
		task.addSubtask(subTask2);
		task.addSubtask(subTask3);
		
		assertEquals(3, task.getDuration());
	}

	/**
	 * test setting duration of a subtask to a number bigger than duration of its parent task.
	 * expect successful operation and duration of a task become equal to duration of a subtask 
	 */
	@Test
	public void testTaskSetDuration10() {
		Task task = new Task();
		task.setDuration(2);
		task.setId(1);
		
		Task subTask1 = new Task();
		subTask1.setId(7);
		subTask1.setDuration(10);
		task.addSubtask(subTask1);
		
		assertEquals(10, task.getDuration());
	}
	
	/**
	 * test setting deliverable of the task to an empty string
	 * expect successful operation; however, the deliverable is set to a default value (none)
	 */
	@Test
	public void testTaskSetDeliverable1() {
		Task task = new Task();
		
		task.setDeliverable("");
		assertEquals("none", task.getDeliverable());
	}
	
	/**
	 * test setting deliverable of the task to along string
	 * expect successful operation
	 */
	@Test
	public void testTaskSetDeliverable2() {
		Task task = new Task();

		task.setDeliverable(stringBufferLong.toString());
		assertEquals(stringBufferLong.toString(), task.getDeliverable());
	}
	
	/**
	 * test setting deliverable of the task to null
	 * expect successful operation; however, the deliverable is set to a default value (none)
	 */
	@Test
	public void testTaskSetDeliverable3() {
		Task task = new Task();

		task.setDeliverable(null);
		assertEquals("none", task.getDeliverable());
	}
	
	/**
	 * test setting deliverable of the task to a string containing wild characters
	 * expect successful operation
	 */
	@Test
	public void testTaskSetDeliverable4() {
		Task task = new Task();
		
		task.setDescription(WILD_STRING);
		assertEquals(WILD_STRING, task.getDescription());
	}
	
	/**
	 * test setting deadline of the task to a valid date (present)
	 * expect successful operation
	 */
	@SuppressWarnings("deprecation")
	@Test
	public void testTaskSetDeadline1() {
		Task task = new Task();
		Date now = Calendar.getInstance().getTime();
		Date testDeadline = Calendar.getInstance().getTime();

		task.setDeadline(now);
		assertTrue(task.getDeadline() instanceof Date);
		
		testDeadline.setMonth(testDeadline.getMonth() + 1);
		task.setDeadline(testDeadline);
		assertTrue(task.getDeadline() instanceof Date);
	}

	/**
	 * test setting deadline of the task to a valid date (past)
	 * expect successful operation
	 */
	@SuppressWarnings("deprecation")
	@Test
	public void testTaskSetDeadline2() {
		Task task = new Task();
		Date testDeadline = Calendar.getInstance().getTime();

		testDeadline.setMonth(testDeadline.getMonth() - 1);
		task.setDeadline(testDeadline);
		assertTrue(task.getDeadline() instanceof Date);
	}
	
	/**
	 * test setting deadline of the task to null
	 * expect successful operation; however the deadline is set to a default value (now)
	 */
	@Test
	public void testTaskSetDeadline3() {
		Task task = new Task();
		
		task.setDeadline(null);
		assertTrue(task.getDeadline() instanceof Date);
	}

	/**
	 * test setting person name (assignee) of the task to an empty string
	 * expect successful operation; however the assignee is set to a default value (nobody)
	 */
	@Test
	public void testTaskSetPerson1() {
		Task task = new Task();
		
		task.setPerson("");
		assertEquals("nobody", task.getPerson());
	}
	
	/**
	 * test setting person name (assignee) of the task to a long string
	 * expect successful operation
	 */
	@Test
	public void testTaskSetPerson2() {
		Task task = new Task();

		task.setPerson(stringBufferLong.toString());
		assertEquals(stringBufferLong.toString(), task.getPerson());
	}
	
	/**
	 * test setting person name (assignee) of the task to null
	 * expect successful operation; however the assignee is set to a default value (nobody)
	 */
	@Test
	public void testTaskSetPerson3() {
		Task task = new Task();

		task.setPerson(null);
		assertEquals("nobody", task.getPerson());
	}
	
	/**
	 * test setting person name (assignee) of the task to a string containing wild characters
	 * expect successful operation
	 */
	@Test
	public void testTaskSetPerson4() {
		Task task = new Task();
		
		task.setPerson(WILD_STRING);
		assertEquals(WILD_STRING, task.getPerson());
	}

	/**
	 * test setting person name (assignee) of the task to a string containing wild characters
	 * expect successful operation
	 */
	@Test
	public void testTaskSetPerson5() {
		Task task = new Task();
		
		task.setPerson("Person 1");
		assertEquals("Person 1", task.getPerson());
	}

	/**
	 * test setting person name (assignee) of the task to value X while the task
	 * has a subtask assigned to nobody (default)
	 * expect successful operation and assignee of the task and subtask both X 
	 */
	@Test
	public void testTaskSetPerson6() {
		Task task = new Task();
		task.setId(1);
		Task subTask = new Task();
		subTask.setId(2);

		task.addSubtask(subTask);
		task.setPerson("X");

		assertEquals(task.getPerson(), "X");
		assertEquals(subTask.getPerson(), "X");
	}
	
	/**
	 * test setting person name (assignee) of the task to value X while the task
	 * has a subtask assigned to X
	 * expect successful operation and assignee of the task and subtask both X 
	 */
	@Test
	public void testTaskSetPerson7() {
		Task task = new Task();
		Task subTask = new Task();
		subTask.setPerson("X");
	
		task.addSubtask(subTask);
		task.setPerson("X");
		
		assertEquals(task.getPerson(), "X");
		assertEquals(subTask.getPerson(), "X");
	}

	/**
	 * test setting person name (assignee) of the task to value X while the task
	 * has a subtask assigned to person Y while X!=Y 
	 * expect successful operation and assignee of the task and subtask both X 
	 */
	@Test
	public void testTaskSetPerson8() {
		Task task = new Task();
		task.setPerson("X");
		task.setId(1);
		
		Task subTask = new Task();
		subTask.setPerson("Y");

		subTask.setId(2);
		task.addSubtask(subTask);
		
		assertEquals(task.getPerson(), "X");
		assertEquals(subTask.getPerson(), "X");
	}

	/**
	 * test setting person name (assignee) of the task to value X while its three subtasks
	 * are assigned to person Y 
	 * expect successful operation and assignee of the task and subtask both X 
	 */
	@Test
	public void testTaskSetPerson9() {
		Task task = new Task();
		task.setId(1);
		
		Task subTask1 = new Task();
		subTask1.setPerson("Y");
		subTask1.setId(2);
		task.addSubtask(subTask1);
		
		Task subTask2 = new Task();
		subTask2.setPerson("Y");
		subTask2.setId(3);
		task.addSubtask(subTask2);
		
		Task subTask3 = new Task();
		subTask3.setPerson("Y");
		subTask3.setId(4);
		task.addSubtask(subTask3);
		
		task.setPerson("X");
		
		assertEquals(task.getPerson(), "X");
		assertEquals(subTask1.getPerson(), "X");
		assertEquals(subTask2.getPerson(), "X");
		assertEquals(subTask3.getPerson(), "X");
	}
	
	/**
	 * test setting person name (assignee) of a subtask to value X while the parent task
	 * is assigned to person Y 
	 * expect successful operation and assignee of the task and subtask both Y
	 */
	@Test
	public void testTaskSetPerson10() {
		Task task = new Task();
		task.setPerson("Y");
		task.setId(1);
		
		Task subTask = new Task();
		subTask.setId(2);
		subTask.setPerson("X");
		task.addSubtask(subTask);
		
		assertEquals(task.getPerson(), "Y");
		assertEquals(subTask.getPerson(), "Y");
	}
	
	/**
	 * test setting person name (assignee) of a subtask to value X while the parent task
	 * is assigned to person Y 
	 * expect successful operation and assignee of the task and subtask both Y 
	 */
	@Test
	public void testTaskSetPerson11() {
		Task task = new Task();
		task.setPerson("Y");
		
		Task subTask = new Task();
		task.addSubtask(subTask);
		
		subTask.setPerson("Y");
		
		assertEquals(task.getPerson(), "Y");
		assertEquals(subTask.getPerson(), "Y");
	}
	/**
	 * test setting person name (assignee) of a subtask that has a subtask to value X while the parent task
	 * is assigned to person Y  and subsubtask is assigned to Z
	 * expect successful operation and assignee of the task and subtask both Y 
	 */
	@Test
	public void testTaskSetPerson12() {
		Task task = new Task();  //parent task
		task.setPerson("Y");
		task.setId(1);
		
		Task subTask = new Task();   // subtask
		subTask.setId(2);
		
		
		Task subSubTask = new Task();  // subtask of the subtask
		subSubTask.setPerson("Z");
		subSubTask.setId(3);
		subTask.addSubtask(subSubTask);
		
		subTask.setPerson("X");
		task.addSubtask(subTask);
		
		assertEquals(task.getPerson(), "Y");
		assertEquals(subTask.getPerson(), "Y");
		assertEquals(subSubTask.getPerson(), "Y");
	}
	/**
	 * test setting beforeId to the id of the task itself
	 * expect successful operation, but beforeId remains unchanged
	 */
	@Test
	public void testTaskSetBeforeId1() {
		
		Task task = new Task();		
		int oldBeforeId = task.getBeforeId();
		
		task.setBeforeId(task.getBeforeId());
		int newBeforeId = task.getBeforeId();
		
		assertEquals(oldBeforeId, newBeforeId);
	}
	
	/**
	 * test setting beforeId to 0 (when task.id != 0)
	 * expect successful operation
	 */
	@Test
	public void testTaskSetBeforeId2() {
		
		Task task = new Task();
		task.setId(1);	
		
		task.setBeforeId(0);
		int newBeforeId = task.getBeforeId();
		
		assertEquals(0, newBeforeId);
	}
	
	/**
	 * test setting beforeId to a positive number (not equal to task.id)
	 * expect successful operation
	 */
	@Test
	public void testTaskSetBeforeId3() {
		
		Task task = new Task();
		task.setId(1);	
		
		task.setBeforeId(10);
		int newBeforeId = task.getBeforeId();
		
		assertEquals(10, newBeforeId);
	}
	
	/**
	 * test setting beforeId to a subtask (which is illegal - subtasks have no dependencies)
	 * expect successful operation, but beforeId remains unchanged: -1
	 */
	@Test
	public void testTaskSetBeforeId4() {
		
		Task task = new Task();
		task.setId(9);
		task.setParent(new Task());	
		
		task.setBeforeId(10);
		int newBeforeId = task.getBeforeId();
		
		assertEquals(-1, newBeforeId);
	}

	/**
	 * test setting beforeId to a negative number
	 * expect successful operation, but beforeId remains unchanged: -1
	 */
	@Test
	public void testTaskSetBeforeId5() {
		
		Task task = new Task();
		
		task.setBeforeId(-10);
		int newBeforeId = task.getBeforeId();
		
		assertEquals(-1, newBeforeId);
	}

	/**
	 * test setting beforeId to a task 
	 * expect successful operation, beforeId is the id of the added task
	 */
	@Test
	public void testTaskSetBeforeId6() {
		
		Task task1 = new Task();
		Task task2 = new Task();
		task2.setId(1);
		
		assertEquals(0, task1.getId());
		assertEquals(1, task2.getId());

		task1.setBeforeId(task2.getId());
		int newBeforeId = task1.getBeforeId();
		
		assertEquals(1, newBeforeId);
	}

	/**
	 * test set parent to null
	 * expect successful operation 
	 */
	@Test
	public void testTaskSetParent1() {
		Task task = new Task();
		task.setParent(null);
		
		assertEquals(null, task.getParent());
	}
	
	/**
	 * test set parent to another task
	 * expect successful operation 
	 */
	@Test
	public void testTaskSetParent2() {
		Task task1 = new Task();
		task1.setId(1);
		Task task2 = new Task();
		task1.setId(2);
		
		task1.setParent(task2);
		
		assertEquals(task1.getParent(), task2);
	}
	
	/**
	 * test set parent to another task that has a subtask
	 * expect successful operation 
	 */
	@Test
	public void testTaskSetParent3() {
		
		// parent task
		Task parent = new Task();
		parent.setId(1);
		Task subtask = new Task();
		subtask.setId(2);
		parent.addSubtask(subtask);
		
		Task task = new Task();
		task.setId(3);
		task.setParent(parent);
		
		assertEquals(task.getParent(), parent);
		assertEquals(subtask.getParent(), parent);
	}
	
	/**
	 * test set parent to another task that has two subtasks
	 * expect successful operation 
	 */
	@Test
	public void testTaskSetParent4() {
		
		// parent task
		Task parent = new Task();
		parent.setId(1);
		Task subtask1 = new Task();
		subtask1.setId(2);
		parent.addSubtask(subtask1);
		Task subtask2 = new Task();
		subtask2.setId(3);
		parent.addSubtask(subtask2);
		
		Task task = new Task();
		task.setId(4);
		task.setParent(parent);
		
		assertEquals(task.getParent(), parent);
		assertEquals(subtask1.getParent(), parent);
		assertEquals(subtask2.getParent(), parent);
	}
	
	/**
	 * test set parent to the same task
	 * expect unsuccessful operation 
	 */
	@Test
	public void testTaskSetParent5() {

		Task task = new Task();
		
		assertEquals(task.getParent(), null);
		
		task.setParent(task);
		
		assertEquals(task.getParent(), null);
	}
	
	/**
	 * test set parent to another task that has the same id
	 * expect unsuccessful operation 
	 */
	@Test
	public void testTaskSetParent6() {

		Task task = new Task();
		task.setId(7);
		
		Task parent = new Task();
		parent.setId(7);
		
		assertEquals(task.getParent(), null);
		task.setParent(parent);
		assertEquals(task.getParent(), null);
	}
	
	/**
	 * test adding null as a subtask
	 * expect unsuccessful operation 
	 */
	@Test
	public void testTaskAddSubtask1() {

		Task task = new Task();
		task.setId(7);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(null);
		assertEquals(task.getSubtasks().size(), 0);
	}
	
	/**
	 * test adding a subtask to a task where the subtask is the task itself
	 * expect unsuccessful operation 
	 */
	@Test
	public void testTaskAddSubtask2() {

		Task task = new Task();
		task.setId(7);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(task);
		assertEquals(task.getSubtasks().size(), 0);
	}
	
	/**
	 * test adding a subtask to a task where the subtask has the same id as the task
	 * expect unsuccessful operation 
	 */
	@Test
	public void testTaskAddSubtask3() {

		Task task = new Task();
		task.setId(7);
		
		Task subtask = new Task();
		subtask.setId(7);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask);
		assertEquals(task.getSubtasks().size(), 0);
	}
	
	/**
	 * test adding a subtask to a task where the subtask has the same id as the task
	 * expect successful operation 
	 */
	@Test
	public void testTaskAddSubtask4() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask = new Task();
		subtask.setId(2);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask);
		assertEquals(task.getSubtasks().size(), 1);
	}
	
	/**
	 * test adding a subtask to a task where the subtask has a different person
	 * expect successful operation 
	 */
	@Test
	public void testTaskAddSubtask5() {

		Task task = new Task();
		task.setId(1);
		task.setPerson("X");
		
		Task subtask = new Task();
		subtask.setId(2);
		subtask.setPerson("Y");
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask);
		assertEquals(task.getSubtasks().size(), 1);
		assertEquals(task.getPerson(), "X");
		assertEquals(subtask.getPerson(), "X");
	}
	
	/**
	 * test adding a subtask to a task where the subtask has a longer duration than the task
	 * expect successful operation 
	 */
	@Test
	public void testTaskAddSubtask6() {

		Task task = new Task();
		task.setId(1);
		task.setDuration(10);
		
		Task subtask = new Task();
		subtask.setId(2);
		subtask.setDuration(20);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask);
		assertEquals(task.getSubtasks().size(), 1);
		assertEquals(task.getDuration(), 20);
		assertEquals(subtask.getDuration(), 20);
	}
	
	/**
	 * test adding a subtask to a task where the subtask has a shorter duration than the task
	 * expect successful operation 
	 */
	@Test
	public void testTaskAddSubtask7() {

		Task task = new Task();
		task.setId(1);
		task.setDuration(10);
		
		Task subtask = new Task();
		subtask.setId(2);
		subtask.setDuration(5);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask);
		assertEquals(task.getSubtasks().size(), 1);
		assertEquals(task.getDuration(), 10);
		assertEquals(subtask.getDuration(), 5);
	}
	
	/**
	 * test adding a subtask to a task where the subtask already has a parent 
	 * expect successful operation 
	 */
	@Test
	public void testTaskAddSubtask8() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask = new Task();
		subtask.setId(2);
		Task parent = new Task();
		parent.setId(3);
		subtask.setParent(parent);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask);
		assertEquals(task.getSubtasks().size(), 1);
		assertEquals(subtask.getParent(),task);
	}
	
	/**
	 * test adding a subtask to a task where the subtask does not a parent 
	 * expect successful operation 
	 */
	@Test
	public void testTaskAddSubtask9() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask = new Task();
		subtask.setId(2);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask);
		assertEquals(task.getSubtasks().size(), 1);
		assertEquals(subtask.getParent(),task);
	}
	
	/**
	 * test adding a subtask to a task where the subtask has three subtasks 
	 * expect successful operation 
	 */
	@Test
	public void testTaskAddSubtask10() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask = new Task();
		subtask.setId(2);
		
		Task subsubtask1 = new Task();
		subsubtask1.setId(3);
		subsubtask1.setParent(subtask);
		Task subsubtask2 = new Task();
		subsubtask2.setId(4);
		subsubtask2.setParent(subtask);
		Task subsubtask3 = new Task();
		subsubtask3.setId(5);
		subsubtask3.setParent(subtask);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask);
		assertEquals(task.getSubtasks().size(), 1);
		assertEquals(subtask.getParent(),task);
	}
	
	/**
	 * test adding a subtask to a task where the subtask has three subtasks and already has a parent
	 * expect successful operation 
	 */
	@Test
	public void testTaskAddSubtask11() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask = new Task();
		subtask.setId(2);
		
		Task subsubtask1 = new Task();
		subsubtask1.setId(3);
		subsubtask1.setParent(subtask);
		Task subsubtask2 = new Task();
		subsubtask2.setId(4);
		subsubtask2.setParent(subtask);
		Task subsubtask3 = new Task();
		subsubtask3.setId(5);
		subsubtask3.setParent(subtask);
		
		Task subtaskParent = new Task();
		subtaskParent.setId(6);
		subtaskParent.addSubtask(subtask);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask);
		assertEquals(task.getSubtasks().size(), 1);
		assertEquals(subtask.getParent(),task);
	}
	
	/**
	 * test adding a subtask twice
	 * expect unsuccessful operation; ; it will added once
	 */
	@Test
	public void testTaskAddSubtask12() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask = new Task();
		subtask.setId(2);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask);
		assertEquals(task.getSubtasks().size(), 1);
		assertEquals(subtask.getParent(),task);
		
		task.addSubtask(subtask);
		assertEquals(task.getSubtasks().size(), 1);
		assertEquals(subtask.getParent(),task);
	}
	
	/**
	 * test adding two subtasks that have the same id
	 * expect unsuccessful operation; only the first one will be added
	 */
	@Test
	public void testTaskAddSubtask13() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask1 = new Task();
		subtask1.setId(2);
		Task subtask2 = new Task();
		subtask2.setId(2);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask1);
		task.addSubtask(subtask2);
		assertEquals(task.getSubtasks().size(), 1);
		assertEquals(subtask1.getParent(),task);
		assertEquals(subtask2.getParent(),null);
	}
	
	/**
	 * test adding three subtasks
	 * expect successful operation 
	 */
	@Test
	public void testTaskAddSubtask14() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask1 = new Task();
		subtask1.setId(2);		
		Task subtask2 = new Task();
		subtask2.setId(3);
		Task subtask3 = new Task();
		subtask3.setId(4);
		
		assertEquals(task.getSubtasks().size(), 0);
		task.addSubtask(subtask1);
		task.addSubtask(subtask2);
		task.addSubtask(subtask3);
		assertEquals(task.getSubtasks().size(), 3);
		assertEquals(subtask1.getParent(),task);
		assertEquals(subtask2.getParent(),task);
		assertEquals(subtask3.getParent(),task);
	}
	
	/**
	 * test removing a null subtask
	 * expect unsuccessful operation 
	 */
	@Test
	public void testTaskRemoveSubtask1() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask1 = new Task();
		subtask1.setId(2);		
		Task subtask2 = new Task();
		subtask2.setId(3);
		Task subtask3 = new Task();
		subtask3.setId(4);
		
		task.addSubtask(subtask1);
		task.addSubtask(subtask2);
		task.addSubtask(subtask3);
		
		assertEquals(task.getSubtasks().size(), 3);
		task.removeSubtask(null);
		assertEquals(task.getSubtasks().size(), 3);
	}
	
	/**
	 * test removing a subtask that was never added
	 * expect unsuccessful operation 
	 */
	@Test
	public void testTaskRemoveSubtask2() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask1 = new Task();
		subtask1.setId(2);		
		Task subtask2 = new Task();
		subtask2.setId(3);
		Task subtask3 = new Task();
		subtask3.setId(4);
		
		task.addSubtask(subtask1);
		task.addSubtask(subtask2);
		task.addSubtask(subtask3);
		
		assertEquals(task.getSubtasks().size(), 3);
		Task subtask4 = new Task();
		subtask4.setId(5);
		task.removeSubtask(subtask4);
		assertEquals(task.getSubtasks().size(), 3);	
		assertTrue(task.getSubtasks().contains(subtask1));
		assertTrue(task.getSubtasks().contains(subtask2));
		assertTrue(task.getSubtasks().contains(subtask3));
	}
	
	/**
	 * test removing a subtask that was added before
	 * expect successful operation 
	 */
	@Test
	public void testTaskRemoveSubtask3() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask1 = new Task();
		subtask1.setId(2);		
		Task subtask2 = new Task();
		subtask2.setId(3);
		Task subtask3 = new Task();
		subtask3.setId(4);
		
		task.addSubtask(subtask1);
		task.addSubtask(subtask2);
		task.addSubtask(subtask3);
		
		assertEquals(task.getSubtasks().size(), 3);
		task.removeSubtask(subtask2);
		assertEquals(task.getSubtasks().size(), 2);
		assertFalse(task.getSubtasks().contains(subtask2));
		assertTrue(task.getSubtasks().contains(subtask1));
		assertTrue(task.getSubtasks().contains(subtask3));
		assertEquals(null, subtask2.getParent());
	}
	
	/**
	 * test removing a subtask twice
	 * expect successful operation from the first removal only 
	 */
	@Test
	public void testTaskRemoveSubtask4() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask1 = new Task();
		subtask1.setId(2);		
		Task subtask2 = new Task();
		subtask2.setId(3);
		Task subtask3 = new Task();
		subtask3.setId(4);
		
		task.addSubtask(subtask1);
		task.addSubtask(subtask2);
		task.addSubtask(subtask3);
		
		assertEquals(task.getSubtasks().size(), 3);
		task.removeSubtask(subtask2);
		task.removeSubtask(subtask2);
		assertEquals(task.getSubtasks().size(), 2);
		assertFalse(task.getSubtasks().contains(subtask2));
		assertTrue(task.getSubtasks().contains(subtask1));
		assertTrue(task.getSubtasks().contains(subtask3));
		assertEquals(null, subtask2.getParent());
	}
	
	/**
	 * test removing a subtask from a task that has only one subtask
	 * expect successful operation 
	 */
	@Test
	public void testTaskRemoveSubtask5() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask1 = new Task();
		subtask1.setId(2);		
		
		task.addSubtask(subtask1);
		
		assertEquals(task.getSubtasks().size(), 1);
		task.removeSubtask(subtask1);
		assertEquals(task.getSubtasks().size(), 0);
		assertFalse(task.getSubtasks().contains(subtask1));
		assertEquals(null, subtask1.getParent());
	}
	
	/**
	 * test removing a subtask from a task that has many subtasks
	 * expect successful operation 
	 */
	@Test
	public void testTaskRemoveSubtask6() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask1 = new Task();
		subtask1.setId(2);		
		Task subtask2 = new Task();
		subtask2.setId(3);
		Task subtask3 = new Task();
		subtask3.setId(4);
		
		task.addSubtask(subtask1);
		task.addSubtask(subtask2);
		task.addSubtask(subtask3);
		
		assertEquals(task.getSubtasks().size(), 3);
		task.removeSubtask(subtask1);
		assertEquals(task.getSubtasks().size(), 2);
		assertFalse(task.getSubtasks().contains(subtask1));
		assertTrue(task.getSubtasks().contains(subtask2));
		assertTrue(task.getSubtasks().contains(subtask3));
		assertEquals(null, subtask1.getParent());
	}
	
	/**
	 * test removing a subtask from a task that has many subtasks
	 * expect successful operation 
	 */
	@Test
	public void testTaskRemoveSubtask7() {

		Task task = new Task();
		task.setId(1);
		
		Task subtask1 = new Task();
		subtask1.setId(2);		
		Task subtask2 = new Task();
		subtask2.setId(3);
		Task subtask3 = new Task();
		subtask3.setId(4);
		
		
		Task subsubtask1 = new Task();
		subsubtask1.setId(5);
		Task subsubtask2 = new Task();
		subsubtask2.setId(6);
		Task subsubtask3 = new Task();
		subsubtask3.setId(7);
		
		subtask1.addSubtask(subsubtask1);
		subtask1.addSubtask(subsubtask2);
		subtask1.addSubtask(subsubtask3);
		
		
		task.addSubtask(subtask1);
		task.addSubtask(subtask2);
		task.addSubtask(subtask3);
		
		assertEquals(task.getSubtasks().size(), 3);
		task.removeSubtask(subtask1);
		assertEquals(task.getSubtasks().size(), 2);
		assertFalse(task.getSubtasks().contains(subtask1));
		assertTrue(task.getSubtasks().contains(subtask2));
		assertTrue(task.getSubtasks().contains(subtask3));
		
		assertEquals(3, subtask1.getSubtasks().size());
		assertEquals(null, subtask1.getParent());
	}
}
